]>
Commit | Line | Data |
---|---|---|
1 | #import "BBObjectCell.h" | |
2 | ||
3 | @implementation BBObjectCell | |
4 | ||
5 | - (NSCellImagePosition)preferredImagePosition { | |
6 | return NSImageAbove; | |
7 | } | |
8 | ||
9 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { | |
10 | BOOL isFirstResponder = [[controlView window] firstResponder] == controlView && ![controlView isKindOfClass:[NSTableView class]]; | |
11 | BOOL dropTarget = ([self isHighlighted] && ([self highlightsBy] & NSChangeBackgroundCellMask) && ![self isBezeled]); | |
12 | ||
13 | NSColor *fillColor; | |
14 | NSColor *strokeColor = [NSColor clearColor]; | |
15 | ||
16 | if (isFirstResponder) { | |
17 | fillColor = [NSColor selectedTextBackgroundColor]; | |
18 | } else { | |
19 | fillColor = [NSColor clearColor]; | |
20 | } | |
21 | ||
22 | if (dropTarget) { | |
23 | fillColor = [NSColor controlAccentColor]; | |
24 | } | |
25 | ||
26 | [fillColor setFill]; | |
27 | [strokeColor setStroke]; | |
28 | ||
29 | NSBezierPath *roundRect = [NSBezierPath bezierPath]; | |
30 | [roundRect appendBezierPathWithRoundedRectangle:cellFrame withRadius:cellRadiusFactor]; | |
31 | [roundRect fill]; | |
32 | ||
33 | [self drawInteriorWithFrame:[self drawingRectForBounds:cellFrame] inView:controlView]; | |
34 | } | |
35 | ||
36 | - (NSRect)titleRectForBounds:(NSRect)theRect | |
37 | { | |
38 | NSRect rect = theRect; | |
39 | rect = NSOffsetRect(rect, 0, -4); | |
40 | return [super titleRectForBounds: rect]; | |
41 | } | |
42 | ||
43 | - (void)drawTextForObject:(QSObject *)drawObject withFrame:(NSRect)cellFrame inView:(NSView *)controlView { | |
44 | if ([self imagePosition] == NSImageOnly) return; | |
45 | ||
46 | NSString *abbrString = nil; | |
47 | if ([controlView respondsToSelector:@selector(matchedString)]) | |
48 | abbrString = [(QSSearchObjectView *)controlView matchedString]; | |
49 | ||
50 | NSString *nameString = nil; | |
51 | NSIndexSet *hitMask = nil; | |
52 | ||
53 | id ranker = [drawObject ranker]; | |
54 | if (ranker && abbrString) | |
55 | nameString = [ranker matchedStringForAbbreviation:abbrString hitmask:&hitMask inContext:nil]; | |
56 | ||
57 | if (!nameString) | |
58 | nameString = [drawObject displayName]; | |
59 | ||
60 | BOOL rankedStringIsName = [nameString isEqualToString:[drawObject displayName]] || nameString == nil; | |
61 | if (!nameString) { | |
62 | // fall back to the identifier if no reasonable name can be found | |
63 | nameString = [drawObject identifier]; | |
64 | } | |
65 | if (!nameString) { | |
66 | // Couldn't find anything sensible to use for the name, fallback to avoid a crash | |
67 | nameString = @"Unknown"; | |
68 | } | |
69 | ||
70 | BOOL useAlternateColor = [controlView isKindOfClass:[NSTableView class]] && [(NSTableView *)controlView isRowSelected:[(NSTableView *)controlView rowAtPoint:cellFrame.origin]]; | |
71 | NSColor *mainColor = (textColor ? textColor : (useAlternateColor ? [NSColor alternateSelectedControlTextColor] : [NSColor controlTextColor])); | |
72 | NSColor *fadedColor = [mainColor colorWithAlphaComponent:0.50]; | |
73 | NSRect textDrawRect = [self titleRectForBounds:cellFrame]; | |
74 | ||
75 | NSMutableAttributedString *titleString = [[[NSMutableAttributedString alloc] initWithString:nameString] autorelease]; | |
76 | [titleString setAttributes:rankedStringIsName ? nameAttributes : detailsAttributes range:NSMakeRange(0, [titleString length])]; | |
77 | ||
78 | // Bring out the matched letters | |
79 | if (abbrString && ![abbrString hasPrefix:@"QSActionMnemonic"]) { | |
80 | [titleString addAttribute:NSForegroundColorAttributeName value:rankedStringIsName ? fadedColor : [fadedColor colorWithAlphaComponent:0.8] range:NSMakeRange(0, [titleString length])]; | |
81 | ||
82 | NSUInteger i = 0; | |
83 | NSUInteger j = 0; | |
84 | NSUInteger hits[[titleString length]]; | |
85 | NSUInteger count = [hitMask getIndexes:(NSUInteger *)&hits maxCount:[titleString length] inIndexRange:nil]; | |
86 | NSDictionary *attributes = @{ | |
87 | NSForegroundColorAttributeName: rankedStringIsName ? mainColor : fadedColor | |
88 | }; | |
89 | for(i = 0; i<count; i += j) { | |
90 | for (j = 1; i+j<count && hits[i+j-1] +1 == hits[i+j]; j++); | |
91 | [titleString addAttributes:attributes range:NSMakeRange(hits[i], j)]; | |
92 | } | |
93 | } else { | |
94 | [titleString addAttribute:NSBaselineOffsetAttributeName value:[NSNumber numberWithDouble:-1.0] range:NSMakeRange(0, [titleString length])]; | |
95 | } | |
96 | // | |
97 | // // Ranked string and nameString aren't the same. Show 'nameString ⟷ rankedString' in the UI | |
98 | // if (!rankedStringIsName && [drawObject displayName].length) { | |
99 | // [titleString addAttribute:NSFontAttributeName value:detailsFont range:NSMakeRange(0,[titleString length])]; | |
100 | // NSMutableAttributedString *attributedNameString = [[NSMutableAttributedString alloc] initWithString:[drawObject displayName]]; | |
101 | // [attributedNameString setAttributes:nameAttributes range:NSMakeRange(0, [[drawObject displayName] length])]; | |
102 | // | |
103 | // [attributedNameString appendAttributedString:[[[NSAttributedString alloc] initWithString:@" ⟷ " attributes:rankedNameAttributes] autorelease]]; | |
104 | // // the replaceCharacters... method inserts the new string into the receiver at the start of the work (range.location and range.length are 0) | |
105 | // [titleString replaceCharactersInRange:NSMakeRange(0,0) withAttributedString:attributedNameString]; | |
106 | // [attributedNameString release]; | |
107 | // } | |
108 | ||
109 | if (showDetails) { | |
110 | NSString *detailsString = [drawObject details]; | |
111 | ||
112 | NSRange returnRange = [detailsString rangeOfString:@"\n"]; | |
113 | if (returnRange.location != NSNotFound) { | |
114 | detailsString = [detailsString substringToIndex:returnRange.location]; | |
115 | } | |
116 | ||
117 | detailsAttributes = [detailsAttributes mutableCopy]; | |
118 | [detailsAttributes setValue:[NSColor grayColor] forKey:NSForegroundColorAttributeName]; | |
119 | ||
120 | if (detailsString && detailsString.length && ![detailsString isEqualToString:nameString]) { | |
121 | [titleString appendAttributedString:[[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"\n%@",detailsString] attributes:detailsAttributes] autorelease]]; | |
122 | } | |
123 | } | |
124 | ||
125 | NSRect centerRect = rectFromSize([titleString size]); | |
126 | centerRect.size.width = NSWidth(textDrawRect); | |
127 | centerRect.size.height = MIN(NSHeight(textDrawRect), centerRect.size.height); | |
128 | [titleString drawInRect:centerRectInRect(centerRect, textDrawRect)]; | |
129 | } | |
130 | ||
131 | - (void)drawSearchPlaceholderWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { | |
132 | NSString *defaultText = NSLocalizedStringWithDefaultValue(@"Type to search", nil, [NSBundle mainBundle], @"Type to search", @"Hint that appears in the first pane of the QS interface when it's empty."); | |
133 | NSSize textSize = [defaultText sizeWithAttributes:nameAttributes]; | |
134 | NSRect textRect = centerRectInRect(rectFromSize(textSize), cellFrame); | |
135 | BOOL isFirstResponder = [[controlView window] firstResponder] == controlView && ![controlView isKindOfClass:[NSTableView class]]; | |
136 | ||
137 | if (isFirstResponder && [controlView isKindOfClass:[QSSearchObjectView class]]) { | |
138 | NSImage *find = [NSImage imageWithSystemSymbolName:@"magnifyingglass.circle.fill" accessibilityDescription:nil]; | |
139 | ||
140 | ||
141 | [find setSize:QSSize16]; | |
142 | NSRect findImageRect = expelRectFromRectOnEdge(centerRectInRect(rectFromSize([find size]), cellFrame), textRect, NSRectEdgeMinX, -2); | |
143 | ||
144 | ||
145 | NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext]; | |
146 | [graphicsContext saveGraphicsState]; | |
147 | CGContextRef context = [graphicsContext CGContext]; | |
148 | CGContextBeginTransparencyLayerWithRect(context, findImageRect, nil); | |
149 | CGContextSetBlendMode(context, kCGBlendModeNormal); | |
150 | [find drawInRect:findImageRect fromRect:rectFromSize([find size]) operation:NSCompositingOperationSourceOver fraction:1]; | |
151 | CGContextSetBlendMode(context, kCGBlendModeSourceIn); | |
152 | CGContextSetFillColorWithColor(context, [[NSColor textColor] CGColor]); | |
153 | CGContextFillRect(context, findImageRect); | |
154 | CGContextEndTransparencyLayer(context); | |
155 | ||
156 | [defaultText drawInRect:textRect withAttributes:nameAttributes]; | |
157 | } | |
158 | } | |
159 | ||
160 | @end |